from django.utils import timezone
import json
from django.shortcuts import render
from django.views import View
from django.contrib.auth.mixins import LoginRequiredMixin
from django.http import JsonResponse
from django_redis import get_redis_connection
from decimal import Decimal

from apps.goods.models import SKU
from apps.users.models import Address
from apps.orders.models import OrderGoods, OrderInfo
from utils.views import LoginRequiredJSONMixin
from django.db import transaction
# Create your views here.
class OrderSettlementView(LoginRequiredMixin, View):
    """结算订单"""

    def get(self, request):
        """提供订单结算页面"""
        # 获取登录用户
        user = request.user

        # 查询当前用户的所有地址信息
        addresses = Address.objects.filter(user=request.user, 
                                               is_deleted=False)

        # 从Redis购物车中查询出被勾选的商品信息
        redis_conn = get_redis_connection('carts')
        redis_cart = redis_conn.hgetall('carts_%s' % user.id)
        cart_selected = redis_conn.smembers('selected_%s' % user.id)
        cart = {}
        for sku_id in cart_selected:
            cart[int(sku_id)] = int(redis_cart[sku_id])

        # 查询商品信息
        sku_list = []
        # 查询商品信息
        skus = SKU.objects.filter(id__in=cart.keys())
        for sku in skus:
            sku_list.append({
                'id':sku.id,
                'name':sku.name,
                'default_image_url':sku.default_image.url,
                'count': cart[sku.id],
                'price':sku.price
            })

        # 补充运费
        freight = Decimal('10.00')

        addresses_list = []
        for address in addresses:
            addresses_list.append({
                'id':address.id,
                'province':address.province.name,
                'city':address.city.name,
                'district':address.district.name,
                'place':address.place,
                'receiver':address.receiver,
                'mobile':address.mobile
            })

        # 渲染界面
        context = {
            'addresses': addresses_list,
            'skus': sku_list,
            'freight': freight,
        }

        return JsonResponse({'code':0,
                                  'errmsg':'ok',
                                  'context':context})
        
class OrderCommitView(LoginRequiredJSONMixin, View):
    """订单提交"""

    def post(self, request):
        """保存订单信息和订单商品信息"""
          # 获取当前要保存的订单数据
        json_dict = json.loads(request.body.decode())
        address_id = json_dict.get('address_id')
        pay_method = json_dict.get('pay_method')
        
        # 验证数据
        if not all([address_id, pay_method]):
            return JsonResponse({'code':400,
                                 'errmsg':'缺少必传参数'})
        try:
            address = Address.objects.get(id=address_id,
                                          user=request.user,
                                          is_deleted=False)
        except Address.DoesNotExist:
            return JsonResponse({'code':400,
                                 'errmsg':'地址错误'})
        if pay_method not in OrderInfo.PAY_METHODS_ENUM.values():
            return JsonResponse({'code':400,
                                 'errmsg':'支付方式错误'})
            
         # 获取登录用户
        user = request.user
        # 生成订单编号：年月日时分秒+用户编号
        order_id = timezone.localtime().strftime('%Y%m%d%H%M%S') + ('%09d' % user.id)
        
        if pay_method == OrderInfo.PAY_METHODS_ENUM['CASH']:
            # 货到付款
            # 订单状态：未付款
            status = OrderInfo.ORDER_STATUS_ENUM['UNSEND']
        else:
            # 非货到付款
            # 订单状态：待支付
            status = OrderInfo.ORDER_STATUS_ENUM['UNPAID']
        
        with transaction.atomic():
            
            ## 事务开始
            save_point = transaction.savepoint()
            
            
            # 创建订单
            order = OrderInfo.objects.create(
                order_id=order_id,
                user=user,
                address=address,
                total_count=0,
                total_amount=Decimal('0'),
                freight=Decimal('10.00'),
                pay_method=pay_method,
                status=status,
            )
            # 从redis读取购物车中被勾选的商品信息
            redis_conn = get_redis_connection('carts')
            redis_cart = redis_conn.hgetall('carts_%s' % user.id)
            selected = redis_conn.smembers('selected_%s' % user.id)
            carts = {}
            for sku_id in selected:
                carts[int(sku_id)] = int(redis_cart[sku_id])
            sku_ids = carts.keys()

            # 遍历购物车中被勾选的商品信息
            for sku_id in sku_ids:
                # 查询SKU信息
                sku = SKU.objects.get(id=sku_id)
                # 判断SKU库存
                sku_count = carts[sku.id]
                if sku_count > sku.stock:
                    ## 事务回滚
                    transaction.savepoint_rollback(save_point)
                    
                    return JsonResponse({'code': 400, 'errmsg': '库存不足'})

                # SKU减少库存，增加销量
                # sku.stock -= sku_count
                # sku.sales += sku_count
                # sku.save()
                
                ## 使用乐观锁
                # 1.先记录某个数据
                old_stock = sku.stock
                # 2. 更新时，对比一下新旧数据是否一致
                new_stock = sku.stock - sku_count
                new_sales = sku.sales + sku_count
                # 3. 提交更新
                res = SKU.objects.filter(id=sku_id, stock=old_stock).update(stock=new_stock, sales=new_sales) # stock = old_stock 判断是否一致
                if res == 0:
                    # 说明别人在你更新之前，已经更新过了
                    transaction.savepoint_rollback(save_point)
                    return JsonResponse({'code': 400, 'errmsg': '下单失败'})

                # 保存订单商品信息 OrderGoods（多）
                OrderGoods.objects.create(
                    order=order,
                    sku=sku,
                    count=sku_count,
                    price=sku.price,
                )

                # 保存商品订单中总价和总数量
                order.total_count += sku_count
                order.total_amount += (sku_count * sku.price)

            # 添加邮费和保存订单信息
            order.total_amount += order.freight
            order.save()
            
            ## 事务提交
            transaction.savepoint_commit(save_point)

        # # 清除购物车中已结算的商品
        # pl = redis_conn.pipeline()
        # pl.hdel('carts_%s' % user.id, *selected)
        # pl.srem('selected_%s' % user.id, *selected)
        # pl.execute()

        # 响应提交订单结果
        return JsonResponse({'code': 0, 'errmsg': '下单成功', 'order_id': order.order_id})